<!--
Date: 2025-08-13
Copyright (c) 2025 CAX Conversion Project
-->
<template>
  <el-dialog :modelValue="arrangementVisible" title="编排" width="1200" @close="buttonClick('cancel')">
    <div class="main" id="algorithmArrangement_main">
      <div class="button-top">
        <!-- 暂存 发布 取消发布-->
        <el-button size="medium" type="primary" :disabled="readOnly" @click="buttonClick('update')">
          <el-icon class="el-icon--left"><Printer /></el-icon>暂存
        </el-button>
        <el-button size="medium" type="success" :disabled="readOnly" @click="buttonClick('publish')">
          <el-icon class="el-icon--left"><Promotion /></el-icon>发布
        </el-button>
        <el-button size="medium" type="info" :disabled="!readOnly" @click="buttonClick('publishRecall')">
          <el-icon class="el-icon--left"><RefreshLeft /></el-icon>取消发布
        </el-button>
        <!-- <el-button size="small" type="primary" @click="buttonClick('cancel')">
          <el-icon class="el-icon--left"><Close /></el-icon>关闭</el-button
        > -->
        <!-- <el-button size="small" type="primary" @click="buttonClick('info')"
          ><el-icon class="el-icon--left"><QuestionFilled /></el-icon>提示</el-button
        > -->
      </div>
      <div class="info">
        注：1.右键节点可以删除、切换算子。2.图中只能拉入一个开始节点和一个结束节点。
      </div>
      <div class="show-box">
        <split-pane :default-percent="splitVertical" split="vertical">
          <!-- left box: 算子节点树组件 -->
          <template v-slot:paneL>
            <el-tree
              class="tree-class"
              ref="operatorTree"
              :data="treeData"
              icon-class="el-icon-arrow-right"
              default-expand-all
              :expand-on-click-node="false"
              draggable
              :allow-drag="allowDrag"
              @node-drag-start="treeNodeMouseDown"
            >
              <template #default="{ node, data }">
                <span class="custom-tree-node">
                  <el-icon class="icon-class" v-if="data?.children?.length > 0"><Folder /></el-icon>
                  <el-icon class="icon-class" v-else-if="data.value === 'start'"><i class="iconfont icon-yuan"></i></el-icon>
                  <el-icon class="icon-class" v-else-if="data.value === 'end'"><i class="iconfont icon-tongzhi"></i></el-icon>
                  <el-icon class="icon-class" v-else><Document /></el-icon>
                  <span class="node-title">{{ node.label }}</span>
                </span>
              </template>
            </el-tree>
          </template>
          <!-- end of left box -->

          <!-- right box -->
          <template v-slot:paneR>
            <split-pane :default-percent="splitHorizontal" split="horizontal" :max-percent="flowMaxPercent">
              <!-- right-top 编排组件 -->
              <template v-slot:paneL>
                <div class="super-flow-base-div" ref="flowContainer" @dblclick="dblclickEvent">
                  <super-flow
                    ref="superFlow"
                    v-bind="arragementConfig"
                    :node-list="nodeList"
                    :link-list="linkList"
                    @flow-node-mousedown="flowNodeClick"
                    @mousedown="canvasMouseDown"
                  >
                    <template v-slot:node="{ meta }">
                      <div v-if="meta.prop === 'operator'" :class="`flow-node flow-node-${meta.headClass}`">
                        <header>
                          <div style="height: 16px; width: 16px">
                            <Document v-if="meta.icon === 'el-icon-s-tools'" />
                          </div>
                          <div class="icontext">{{ ' ' + meta.name }}</div>
                        </header>
                        <span>{{ meta.parent ? meta.parent.join(' / ') : '' }}</span>
                        <el-tooltip v-show="meta.description" :content="meta.description" placement="bottom">
                          <section>{{ nameDisplay(meta.description) }}</section>
                        </el-tooltip>
                      </div>
                      <span v-else :class="`flow-node flow-node-${meta.headClass}`">
                        <i :class="meta.icon"></i>
                      </span>
                    </template>
                  </super-flow>
                </div>
              </template>
              <!-- end of right-top -->

              <!-- right bottom 属性展示table -->
              <template v-slot:paneR>
                <div class="table-div">
                  <el-table :data="tableData" size="mini" :header-cell-style="{ background: '#ffffff', color: '#606266' }">
                    <el-table-column prop="name" label="当前" />
                    <el-table-column prop="description" label="详细信息" />
                  </el-table>
                </div>
              </template>
              <!-- end of right-bottom  -->
            </split-pane>
          </template>
          <!-- end of right box -->
        </split-pane>
      </div>
    </div>
    <OperatorSelect
      @handleEvent="handleEvent"
      :contextData="myContextData"
      :operatorSelectVisible="operatorSelectVisible"
      v-if="operatorSelectVisible"
    />
    <OperatorConfig
      @handleEvent="handleEvent"
      :contextData="myContextData"
      :operatorConfigVisible="operatorConfigVisible"
      v-if="operatorConfigVisible"
    />
  </el-dialog>
</template>
  
<script lang="jsx">
import OperatorSelect from './OperatorSelect';
import OperatorConfig from './OperatorConfig';
import {operatorType} from '../algorithmLibrary.js';
import { Close, QuestionFilled, RefreshLeft, Tools,Promotion ,Printer, Document} from '@element-plus/icons-vue';
import {getAlgorithmArrangement,getOperatorInfo,algorithmArrangementSave} from  '@/api/algorithmLibrary';
import { ElMessageBox,ElMessage } from 'element-plus';

export default {
  name:"AlgorithmArrangement",
  props: {
    contextData: {
      type: Object,
      default: () => ({})
    },
    arrangementVisible: {
      type: Boolean
    }
  },
  components:{
    OperatorSelect,
    OperatorConfig
  },
  beforeDestroy(){
    document.removeEventListener('mousemove', this.docMousemove);
    document.removeEventListener('mouseup', this.docMouseup);
  },
  mounted() {
    
    // 初始化信息表格
    this.updatedTable(null);
    // 拖曳添加所需事件
    document.addEventListener('mousemove', this.docMousemove);
    document.addEventListener('mouseup', this.docMouseup);
    // 树上除了开始结束，添加所有算子类型
    
    this.treeData = this.treeData.concat(operatorType);
    
    this.addInfoToTree(this.treeData);
    // 获取allNodeList经格式转换后装载
    getAlgorithmArrangement({analysisRefId: this.contextData._id,}).then((res) => {
      const data = this.nodeListSplit(res.data);
      this.nodeList = data.nodeList;
      this.linkList = data.linkList;
    });
  },
  data() {
    return {
      publishFlag: this.contextData.isPublished,
      operatorSelectVisible:false,
      operatorConfigVisible:false,
    //   publishFlag: false,
      // split 比例设置
      splitVertical: 20,
      splitHorizontal: 86,
      flowMaxPercent: 86,
      // 设置flow中节点尺寸
      startEndW: 50,
      startEndH: 50,
      operatorW: 230,
      operatorH: 120,
      // 下方属性展示数据
      tableData: [],
      // 算子类型树数据
      treeData: [
        { label: '开始节点', value: 'start' },
        { label: '结束节点', value: 'end' }
      ],
      currentNode: {}, // 当前选中的节点
      myContextData: {},
      // 算法编排图形配置
      arragementConfig: {
        // 定义画面起点坐标
        origin: [717, 366],
        // 空白处右键菜单
        graphMenu: [
          [
            {
              label: '全选',
              selected: (graph, coordinate) => {
                graph.selectAll();
              }
            }
          ]
        ],
        // 右键node菜单
        nodeMenu: [
          [
            {
              label: '删除',
              disable: false,
              selected(node, coordinate) {
                node.remove();
              }
            }
          ],
          [
            {
              label: '选择算子',
              hidden(node) {
                return node.meta.prop === 'startAnalysis' || node.meta.prop === 'endAnalysis';
              },
              selected: (node, coordinate) => {
                this.currentNode = node;
                const typeObj = {
                  application_type: node.meta.parent[0],
                  material_type: node.meta.parent[1],
                  algorithm_type: node.meta.operator_type
                };
                this.myContextData = { typeObj };
                this.operatorSelectVisible = true;
              }
            }
          ],
          [
            {
              label: '配置关联上游参数',
              hidden(node) {
                return node.meta.prop === 'startAnalysis' || node.meta.prop === 'endAnalysis' || !('operator_ref_id' in node.meta);
              },
              selected: (node, coordinate) => {
                this.currentNode = node;
                this.myContextData = {
                  analysis_ref_id: this.contextData._id,
                  operator_ref_id: node.meta.operator_ref_id
                };
                this.operatorConfigVisible = true;
              }
            }
          ]
        ],
        // 右键link菜单
        linkMenu: [
          [
            {
              label: '删除',
              disable: false,
              selected: (link, coordinate) => {
                link.remove();
              }
            }
          ],
          [
            {
              label: '编辑',
              disable: false,
              selected: (link, coordinate) => {
                this.editLink(link);
              }
            }
          ]
        ],
        // 数据字段定义
        relationMark: '_id',
        startMark: 'source_ref_id',
        endMark: 'target_ref_id',
        // link可拉入校验
        enterIntercept(formNode, toNode, graph) {
          const formType = formNode.meta.prop;
          switch (toNode.meta.prop) {
            case 'startAnalysis':
              return false;
            case 'operator':
              return ['startAnalysis', 'operator'].includes(formType);
            case 'endAnalysis':
              return ['operator'].includes(formType);
            default:
              return true;
          }
        },
        // link可拉出校验
        outputIntercept(node, graph) {
          return !(node.meta.prop === 'endAnalysis');
        },
        linkDesc(link) {
          return link.meta ? link.meta.description : '';
        }
      },
      nodeList: [],
      linkList: [],
      // 拖曳添加相关配置
      dragConf: {
        isDown: false,
        isMove: false,
        offsetTop: 0,
        offsetLeft: 0,
        clientX: 0,
        clientY: 0,
        ele: null,
        info: null
      },
      activeName: 'process'
    };
  },
  computed: {
    // 发布和暂存按钮状态
    readOnly() {
      return this.publishFlag == true;
    }
  },
  methods: {
    // 树渲染
    renderContent(h, { node, data }) {
        let iconHead = 'Folder';
        if (data.children === undefined || data.children.length === 0) {
          iconHead = 'Tools';
          if (data.value === 'start') {
            iconHead = 'iconfont icon-yuan';
          } else if (data.value === 'end') {
            iconHead = 'iconfont icon-tongzhi';
          }
        }
        return (
          <span class="tree-render-div">
            <span>
              <i class={iconHead} style="color: #c1bebe;padding-right: 5px; font-size: 120%;"></i>
              <span>{node.label}</span>
            </span>
          </span>
        );
    },
    saveData(data,type){
        // 数据转义
        const linkData = data.linkList || [];
        const nodeData = data.nodeList || [];
        linkData.forEach(el=>{
            el.nodeType = el.node_type;
            el.sourceRefId = el.source_ref_id;
            el.targetRefId = el.target_ref_id;
        })
        nodeData.forEach(el=>{
            el.nodeType = el.node_type;
            if(el.operator_ref_id){
                el.operatorRefId = el.operator_ref_id
            }
            if(el.operator_type){
                el.operatorType = el.operator_type
            }
        })
        const params = {
            status:type,
            analysisRefId:this.contextData._id,
            arrangement:{nodeList:nodeData,linkList:linkData}
        }
        algorithmArrangementSave(params).then(res=>{
            if(type !== 'update'){
              ElMessage({ showClose: true, message: type==='publish'?'发布成功。':'取消成功。', type: 'success' });
              this.$emit('handle-event',{refresh:true});
            }else{
              ElMessage({ showClose: true, message: '暂存成功。', type: 'success' });
            }   
        })
    },
    // 下方按钮点击事件
    buttonClick(id) {
      if (id === 'cancel') {
        this.$emit('handle-event', {refresh:false});
      } else if (id === 'publish') {
        // 校验至少有开始、结束节点、连线
        if (this.checkGraph()) {
          if (this.checkOperatorSelected()) {
            // 通过校验，是否确认发布
            ElMessageBox.confirm('是否确认发布？', '警告', {
                confirmButtonText: '确定',
                cancelButtonText: '取消',
                type: 'warning'
            }).then(() => {
                const data = this.getGraphData();
                this.saveData(data,'publish');
                this.publishFlag = true;
            });
          } else {
            ElMessage({ showClose: true, message: '编排图上的所有算子节点都需要选择具体的算子。', type: 'warning' });
          }
        } else {
          ElMessage({ showClose: true, message: '算法编排至少应包含开始节点、结束节点、算子节点和连线。', type: 'warning' });
        }
      } else if (id === 'update') {
        const data = this.getGraphData();
        this.saveData(data,'update');
      } else if (id === 'publishRecall') {
        ElMessageBox.confirm('是否取消发布？', '警告', {
            confirmButtonText: '确定',
            cancelButtonText: '取消',
            type: 'warning'
        }).then(() => {
            const data = this.getGraphData();
            this.saveData(data,'unpublish');
            this.publishFlag = false;
        });   
      } else if (id === 'info') {
        ElMessage({
            message: h('div', [
                '提示：',
                h('br'),
                '1、右键节点可以删除、切换算子。',
                h('br'),
                '2、图中只能拉入一个开始节点和一个结束节点。'
            ]),
            showClose: true,
            type: 'success'
        })
      }
    },
    
    // 右键选择算子的回调
    handleEvent(event) {
      if (event.parms === 'operator-select') {
        // 更新图上内容
        this.operatorSelectVisible = false;
        this.currentNode.meta.description = event.data.operatorName;
        this.currentNode.meta.operator_ref_id = event.data._id;
      }
      if(event.parms === 'close-config'){
        this.operatorConfigVisible = false;
      }
      if(event.parms === 'operator-select-close'){
        this.operatorSelectVisible = false;
      }
      
    },
    getDivPopShow(component, title, width) {
      this.divPopupConfig.width = width;
      this.divPopupConfig.title = title;
      this.divPopupConfig.component = component;
      this.openDiv();
    },
    // 双击事件
    dblclickEvent(e) {
      // link双击编辑
    //   const link = this.$refs.superFlow.graph.mouseOnLink;
    //   const node = this.$refs.superFlow.graph.mouseonNode;
    //   if (link !== null) {
    //     // 双击link
    //     this.editLink(link);
    //   } else if (node !== null) {
    //     // 双击node
    //     if (node.meta.operator_ref_id !== undefined) {
    //       this.myContextData = { data: { _id: node.meta.operator_ref_id } };
    //       this.getDivPopShow(OperatorParameter, '算子参数', '1200px');
    //     }
    //   }
    },
    // 编辑link内容
    editLink(link) {
      this.$prompt('连线描述', '编辑', {
        inputValue: link.meta ? link.meta.description : null,
        closeOnClickModal: false,
        closeOnPressEscape: false,
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        confirmButtonClass: 'el-icon-check',
        cancelButtonClass: 'el-icon-close'
      })
        .then(({ value }) => {
          if (!link.meta) {
            link.meta = {};
          }
          link.meta.description = value;
        })
        .catch(() => {
          this.msgInfo('已取消');
        });
    },

    // 输入的数据拆分为符合要求的nodeList、linkList
    nodeListSplit(data) {
      const newData = { nodeList: [], linkList: [] };
      data.forEach((item) => {
        if (item.nodeType === 'sequenceFlow') {
          // link
          item.meta = {
            analysis_ref_id: item.analysisRefId,
            description: item.description
          };
          item.analysis_ref_id = item.analysisRefId;
          item.node_type = item.nodeType;
          item.source_ref_id = item.sourceRefId;
          item.target_ref_id = item.targetRefId;
          newData.linkList.push(item);
        } else {
          // node
          const newObj = {
            _id: item._id,
            coordinate: item.coordinate,
            meta: {
              analysis_ref_id: item.analysisRefId,
              prop: item.nodeType,
              name: item.label
            }
          };
          if (item.nodeType === 'startAnalysis') {
            // 开始节点
            newObj.width = this.startEndW; // 目前做法:长宽前端静态写，不存后端 原：90
            newObj.height = this.startEndW;
            newObj.meta.headClass = item.nodeType; // 节点颜色配置
            newObj.meta.icon = 'iconfont icon-yuan';
            newObj.meta.class = 'start-end-node';
          } else if (item.nodeType === 'endAnalysis') {
            // 结束节点
            newObj.width = this.startEndW;
            newObj.height = this.startEndW;
            newObj.meta.headClass = item.nodeType;
            newObj.meta.icon = 'iconfont icon-rough-circle';
            newObj.meta.class = 'start-end-node';
          } else {
            // 三类算子节点 补充存储算法相关信息
            newObj.width = this.operatorW;
            newObj.height = this.operatorH;
            newObj.meta.parent = item.parent;
            newObj.meta.headClass = item.operatorType;
            newObj.meta.icon = 'el-icon-s-tools';
            newObj.meta.description = item.description;
            newObj.meta.operator_ref_id = item.operatorRefId;
            newObj.meta.operator_type = item.operatorType;
          }
          newData.nodeList.push(newObj);
        }
      });
      return newData;
    },
    // 校验所有算子节点已选算子
    checkOperatorSelected() {
      let flag = true;
      const graph = this.$refs.superFlow.graph.toJSON();
      graph.nodeList.forEach((item) => {
        if (item.meta.prop === 'operator' && item.meta.operator_ref_id === undefined) {
          flag = false; // 存在没有算子id的算子节点
        }
      });
      return flag;
    },
    // 校验至少有开始、结束节点、连线
    checkGraph() {
      const graph = this.$refs.superFlow.graph.toJSON();
      let haveStart = false;
      let haveEnd = false;
      let haveLink = false;
      graph.nodeList.forEach((item) => {
        if (item.meta.prop === 'startAnalysis') {
          haveStart = true;
        }
        if (item.meta.prop === 'endAnalysis') {
          haveEnd = true;
        }
      });
      if (graph.linkList.length > 0) {
        haveLink = true;
      }
      return haveStart && haveEnd && haveLink;
    },
    // 返回当前图中的编排信息
    getGraphData() {
      const graph = this.$refs.superFlow.graph.toJSON();
      const data = { nodeList: [], linkList: [] };
      // analysis_ref_id 不存,外层单独字段发

      graph.nodeList.forEach((item) => {
        item.node_type = item.meta.prop;
        item.label = item.meta.name;
        if (item.node_type !== 'startAnalysis' && item.node_type !== 'endAnalysis') {
          // 不存description，目前放算子名称，后端根据operator_ref_id查询返回
          item.operator_ref_id = item.meta.operator_ref_id;
          item.operator_type = item.meta.operator_type;
          item.parent = item.meta.parent;
        }
        delete item.width;
        delete item.height;
        delete item.meta;
        data.nodeList.push(item);
      });

      graph.linkList.forEach((item) => {
        item.node_type = 'sequenceFlow';
        if (item.meta && item.meta.description) {
          item.condition = item.meta.description;
        }
        delete item.width;
        delete item.height;
        delete item.meta;
        data.linkList.push(item);
      });
      return data;
    },

    // 按下拖曳相关逻辑
    // 为树节点添加绘图需要的算子类型信息
    addInfoToTree(data, parent = []) {
      data.forEach((item) => {
        if (item?.children !== undefined && item?.children.length > 0) {
          parent.push(item.value);
          const itemParent = JSON.parse(JSON.stringify(parent));
          this.addInfoToTree(item.children, itemParent);
          parent.pop();
        } else {
          if (item?.value === 'start') {
            item.info = {
              width: this.startEndW,
              height: this.startEndH,
              meta: {
                prop: 'startAnalysis',
                headClass: 'startAnalysis',
                icon: 'iconfont icon-yuan',
                class: 'start-end-node'
              }
            };
          } else if (item?.value === 'end') {
            item.info = {
              width: this.startEndW,
              height: this.startEndH,
              meta: {
                prop: 'endAnalysis',
                name: 'end',
                headClass: 'endAnalysis',
                icon: 'iconfont icon-tongzhi',
                class: 'start-end-node'
              }
            };
          } else {
            // operator
            item.info = {
              width: this.operatorW,
              height: this.operatorH,
              meta: {
                parent, // 用于右键筛选算子
                prop: 'operator',
                name: item?.value.replace(/-[a-z]/g, (str1) => str1.substr(-1).toUpperCase()), // "Admissible Stress" 下划转驼峰
                description: '',
                headClass: item?.value, // "admissible_stress"
                operator_type: item?.value,
                icon: 'el-icon-s-tools'
              }
            };
          }
        }
      });
    },
    // 控制节点是否可以被拖曳
    allowDrag(node) {
      let flag = true;
      // 开始结束节点只能添加一个
      const graph = this.$refs.superFlow.graph;
      // 只有叶子节点可以被拖曳
      if (node.childNodes.length !== 0) {
        flag = false;
      } else if (node.data.info.meta.prop === 'endAnalysis' && graph.nodeList.find((node) => node.meta.prop === 'endAnalysis')) {
        flag = false;
        // this.msgWarning("只能存在一个结束节点");
      } else if (node.data.info.meta.prop === 'startAnalysis' && graph.nodeList.find((node) => node.meta.prop === 'startAnalysis')) {
        flag = false;
      }
      return flag;
    },
    // 树节点 点下 获取点的信息
    treeNodeMouseDown(node, evt) {
      const { clientX, clientY, currentTarget } = evt;
      const { top, left } = evt.currentTarget.getBoundingClientRect();
      const conf = this.dragConf;
      const ele = currentTarget.cloneNode(true);

      Object.assign(this.dragConf, {
        offsetLeft: clientX - left,
        offsetTop: clientY - top,
        clientX: clientX,
        clientY: clientY,
        info: JSON.parse(JSON.stringify(node.data.info)),
        ele,
        isDown: true
      });

      ele.style.position = 'fixed';
      ele.style.margin = '0';
      ele.style.top = clientY - conf.offsetTop + 'px';
      ele.style.left = clientX - conf.offsetLeft + 'px';
      const dom = document.getElementById('algorithmArrangement_main');
      dom.appendChild(this.dragConf.ele);
    },
    // 按下拖动
    docMousemove({ clientX, clientY }) {
      const conf = this.dragConf;
      if (conf.isMove) {
        conf.ele.style.top = clientY - conf.offsetTop + 'px';
        conf.ele.style.left = clientX - conf.offsetLeft + 'px';
      } else if (conf.isDown) {
        // 鼠标移动量大于 5 时 移动状态生效
        conf.isMove = Math.abs(clientX - conf.clientX) > 5 || Math.abs(clientY - conf.clientY) > 5;
      }
    },
    // 拖动后松开
    docMouseup({ clientX, clientY }) {
      const conf = this.dragConf;
      conf.isDown = false;

      if (conf.isMove) {
        const { top, right, bottom, left } = this.$refs.flowContainer.getBoundingClientRect();

        // 判断鼠标是否进入 flow container
        if (clientX > left && clientX < right && clientY > top && clientY < bottom) {
          // 获取拖动元素左上角相对 super flow 区域原点坐标
          const coordinate = this.$refs.superFlow.getMouseCoordinate(clientX - conf.offsetLeft, clientY - conf.offsetTop);
          // 添加节点
          this.$refs.superFlow.addNode({
            coordinate,
            ...conf.info
          });

          // 拖入时高亮当前节点
          this.flowNodeClick(conf.info);
        }

        conf.isMove = false;
      }

      if (conf.ele) {
        conf.ele.remove();
        conf.ele = null;
      }
    },
    // 节点高亮相关逻辑
    // 选中节点事件
    flowNodeClick(node, evt = null) {
      // 禁止mousedown事件冒泡，禁止外层事件响应
      if (evt !== null) {
        evt.stopPropagation();
      }
      const graph = this.$refs.superFlow.graph;
      // 高亮当前选中的节点
      // 不使用set方式赋值 点击空白处取消高亮不重新渲染
      node.meta.borderClass = 'node-selected';
    //   this.$set(node.meta, 'borderClass', 'node-selected');
      // 清理上一次选中的高亮效果：
      // 组件将每次被选中的节点数据放在nodeList的最后一个，倒数第二个节点即为上一次选中的节点
      const length = graph.nodeList.length;
      if (length > 1) {
        graph.nodeList[length - 2].meta.borderClass = '';
      }

      // 联动表格数据
      this.updatedTable(node);
    },
    updatedTable(node) {
      if (node !== null && node.meta.prop === 'operator') {
        // operator类型节点 已选算子 显示算子具体信息
        if (node.meta.operator_ref_id !== undefined) {
          //通过operator_ref_id查询算子信息
          getOperatorInfo({operatorRefId:node.meta.operator_ref_id}).then((res) => {
            const operator = this.fieldPack(res.data);
            this.tableData = [
              {
                name: operator.operatorName,
                description: operator.calculate_object.join(' 、 ')
              }
            ];
          });
        } else {
          // operator类型节点 未选算子 显示节点已有信息
          this.tableData = [
            {
              name: node.meta.operator_type,
              description: node.meta.parent.join('/')
            }
          ];
        }
      } else {
        const calculateArr = this.contextData.calculateObjects.map(el=>{
            return `${el.objectType},${el.objectName}`;
        })
        this.tableData = [
          {
            name: this.contextData.analysisType,
            description: calculateArr.join(' 、 ')
          }
        ];
      }
    },
    // 点击画布空白位置取消高亮
    canvasMouseDown(evt) {
      console.log('canvasMouseDown');
      // 清除上一次选中的高亮效果：
      const graph = this.$refs.superFlow.graph;
      const length = graph.nodeList.length;
      graph.nodeList[length - 1].meta.borderClass = '';
      this.$forceUpdate(); // 强制刷新渲染
      // 联动表格数据
      this.updatedTable(null);
    },
    // 级联字段打包 （处理算子信息）
    fieldPack(data) {
      // data:{}
      const newObj = [];
      data.calculateObjects.forEach((objItem) => {
        const temp = [];
        temp.push(objItem.objectType);
        temp.push(objItem.objectName);
        newObj.push(temp);
      });
      data.calculate_object = newObj;
      // type 3个type均为必填项
      const typeArr = [];
      typeArr.push(data.applicationType);
      typeArr.push(data.materialType);
      typeArr.push(data.algorithmType);
      data.type = typeArr;
      return data;
    },
    // 算子名称过长时多余部分显示省略号
    nameDisplay(name) {
      let newName = name;
      if (name.length > 52) {
        // 56个字符刚好两行
        newName = name.substring(0, 52) + '...';
      }
      return newName;
    }
  }
};
</script>
  
  <style lang="scss" scoped>
.main {
  padding: 5px 15px 15px 15px;
  .info {
    font-size: 12px;
    color: red;
    padding-bottom: 10px;
  }
}
// 布局 注释的部分是弹窗白底组件边框版本
.show-box {
  border: 1px solid #e2e2e2;
  height: 700px;
  width: 100%; // 宽度在弹窗config中
}
.tree-class {
  height: 100%;
  padding: 10px;
  overflow: scroll;
  .custom-tree-node {
    display: flex;
    .icon-class {
      color: rgba(193, 190, 190);
      font-size: 120%;
      .start::before {
        content: '\e600';
      }
    }
    .node-title {
      padding-left: 5px;
      color: #787a7d;
    }
  }
}
.table-div {
  height: 100%;
  width: 100%;
  overflow: auto;
  padding: 10px;
}
.button-top {
  padding-bottom: 10px;
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-start;
}
.icontext {
  // 节点名称与图标添加间隔
  padding-left: 5px;
}
:deep().super-flow-base-div {
  height: 100%;
  width: 100%;
  margin: 0 auto;
  // 背景换为白色，添加边框 原版背景色： #f5f5f5
  background-color: #ffffff;

  .super-flow__node {
    background-color: #f9f9f9; // 所有节点底色
    border-radius: 5px; // 圆角

    .flow-node {
      > header {
        font-size: 14px;
        height: 32px;
        line-height: 32px;
        padding: 0 12px;
        color: #ffffff;
      }

      > section {
        text-align: center;
        line-height: 20px;
        overflow: hidden;
        padding: 3px 12px;
        word-break: break-all;
      }

      &.flow-node-work_stress {
        > header {
          color: green;
          border-radius: 16px 16px 0px 0px; // 圆角
          display: flex;
        }
        > span {
          color: green;
          padding-left: 12px;
          font-size: 12px;
        }
      }

      &.flow-node-admissible_stress {
        > header {
          border-radius: 16px 16px 0px 0px; // 圆角
          color: palevioletred;
          display: flex;
        }
        > span {
          color: palevioletred;
          padding-left: 12px;
          font-size: 12px;
        }
      }

      &.flow-node-work_strain {
        > header {
          border-radius: 16px 16px 0px 0px; // 圆角
          color: blueviolet;
          display: flex;
        }
        > span {
          color: blueviolet;
          padding-left: 12px;
          font-size: 12px;
        }
      }

      &.flow-node-admissible_strain {
        > header {
          border-radius: 16px 16px 0px 0px; // 圆角
          color: orange;
          display: flex;
        }
        > span {
          color: orange;
          padding-left: 12px;
          font-size: 12px;
        }
      }

      &.flow-node-work_load {
        > header {
          border-radius: 16px 16px 0px 0px; // 圆角
          color: blue;
          display: flex;
        }
        > span {
          color: blue;
          padding-left: 12px;
          font-size: 12px;
        }
      }

      &.flow-node-admissible_load {
        > header {
          border-radius: 16px 16px 0px 0px; // 圆角
          color: peru;
          display: flex;
        }
        > span {
          color: peru;
          padding-left: 12px;
          font-size: 12px;
        }
      }

      &.flow-node-MS {
        > header {
          border-radius: 16px 16px 0px 0px; // 圆角
          color: darkred;
          display: flex;
        }
        > span {
          color: darkred;
          padding-left: 12px;
          font-size: 12px;
        }
      }

      &.flow-node-stress_spectrum {
        > header {
          border-radius: 16px 16px 0px 0px; // 圆角
          color: rgb(0, 60, 139);
          display: flex;
        }
        > span {
          color: rgb(0, 60, 139);
          padding-left: 12px;
          font-size: 12px;
        }
      }

      &.flow-node-cfq {
        > header {
          border-radius: 16px 16px 0px 0px; // 圆角
          color: purple;
          display: flex;
        }
        > span {
          color: purple;
          padding-left: 12px;
          font-size: 12px;
        }
      }
    }
  }

  .start-end-node {
    border: 4px solid transparent; // 占位：后续高亮不会发生icon偏移
    border-radius: 25px;

    .flow-node {
      display: flex;
      height: 100%;
      align-items: center;
      &.flow-node-startAnalysis {
        > i {
          font-size: 61px;
          margin-left: -9px;
        }
      }

      &.flow-node-endAnalysis {
        > i {
          font-size: 61px;
          margin-left: -9px;
        }
      }
    }
  }

  .start-end-node:hover {
    box-shadow: 1px 2px 12px rgba(0, 0, 0, 0.4);
  }
  // 节点选中高亮
  .node-selected {
    // 箭头高亮：'#FF0000' 节点高亮较粗，颜色调暗
    border: 4px solid #e64242 !important; // orange
  }
}
.read-only {
  pointer-events: none;
}
</style>
  